//
//  GLView.swift
//  learn-gl-es-swift
//
//  Created by LimitLiu on 2019/7/2.
//  Copyright © 2019 LimitLiu. All rights reserved.
//

import UIKit
import OpenGLES.ES2

class GLView: UIView {
    weak var delegate: GLViewDelegate!
    var defaultFrameBuffer: GLuint = 0
    var colorRenderBuffer: GLuint = 0
    var drawableWidth: GLint {
        var backingWidth: GLint = 0
        glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER),
                                     GLenum(GL_RENDERBUFFER_WIDTH),
                                     &backingWidth)
        return backingWidth
    }
    var drawableHeight: GLint {
        var backingHeight: GLint = 0
        glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER),
                                     GLenum(GL_RENDERBUFFER_HEIGHT),
                                     &backingHeight)
        return backingHeight
    }
    
    private var backingContext: EAGLContext!
    var context: EAGLContext! {
        set {
            guard backingContext != newValue else {
                fatalError()
            }
            if backingContext != nil {
                if defaultFrameBuffer != 0 {
                    glDeleteFramebuffers(1, &defaultFrameBuffer)
                    defaultFrameBuffer = 0
                }
                if colorRenderBuffer != 0 {
                    glDeleteFramebuffers(1, &colorRenderBuffer)
                    colorRenderBuffer = 0
                }
            }
            
            backingContext = newValue
            EAGLContext.setCurrent(backingContext)
            if backingContext != nil {
                glGenFramebuffers(1, &defaultFrameBuffer)
                glBindFramebuffer(GLenum(GL_FRAMEBUFFER), defaultFrameBuffer)
                glGenRenderbuffers(1, &colorRenderBuffer)
                glBindRenderbuffer(GLenum(GL_RENDERBUFFER), colorRenderBuffer)
                glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER),
                                          GLenum(GL_COLOR_ATTACHMENT0),
                                          GLenum(GL_RENDERBUFFER),
                                          colorRenderBuffer)
            }
        }
        
        get {
            return backingContext
        }
    }
    
    override class var layerClass : AnyClass {
        return CAEAGLLayer.self
    }
    
    deinit {
        context = nil
    }
    
    init(frame: CGRect, context: EAGLContext) {
        super.init(frame: frame)
        if let eaglLayer: CAEAGLLayer = self.layer as? CAEAGLLayer {
            eaglLayer.drawableProperties = [
                kEAGLDrawablePropertyRetainedBacking: false,
                kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
            ]
        }
        self.context = context
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        if let delegate = self.delegate {
            delegate.glkView(self, drawIn: rect)
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if let eaglLayer = self.layer as? CAEAGLLayer {
            context.renderbufferStorage(Int(GL_RENDERBUFFER), from: eaglLayer)
            glBindRenderbuffer(GLenum(GL_RENDERBUFFER), colorRenderBuffer)
            let status = glCheckFramebufferStatus(GLenum(GL_FRAMEBUFFER))
            if status != GL_FRAMEBUFFER_COMPLETE {
                print("failed to make complete frame buffer object \(status)")
            }
        }
    }
    
    func display() {
        glViewport(0, 0, drawableWidth, drawableHeight)
        draw(bounds)
        context.presentRenderbuffer(Int(GL_RENDERBUFFER))
    }
}
